package com.ld.security.shop.crawler.modules.re.crawler;

import com.gargoylesoftware.htmlunit.BrowserVersion;
import com.gargoylesoftware.htmlunit.CookieManager;
import com.gargoylesoftware.htmlunit.NicelyResynchronizingAjaxController;
import com.gargoylesoftware.htmlunit.WebClient;
import com.gargoylesoftware.htmlunit.html.HtmlPage;
import com.ld.security.common.core.util.GenericUtil;
import com.ld.security.common.core.util.ReflectionUtil;
import com.ld.security.common.core.util.UuidUtil;
import com.ld.security.shop.crawler.modules.re.constant.CrawlerConstant;
import com.ld.security.shop.crawler.modules.re.entity.CrawlerEntity;
import com.ld.security.shop.crawler.modules.re.service.IReBookService;
import com.ld.security.shop.crawler.modules.re.service.IReDetailsService;
import lombok.SneakyThrows;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import org.springframework.beans.factory.annotation.Autowired;

import java.util.HashMap;
import java.util.Map;

public abstract class BaseCrawler<E extends CrawlerEntity>{


    protected CrawlerConstant.projectCode projectCode;

    private boolean dyn;


    @Autowired
    protected IReDetailsService iReDetailsService;

    @Autowired
    protected IReBookService iReBookService;

    public BaseCrawler( CrawlerConstant.projectCode projectCode) {
        this.projectCode = projectCode;
    }

    public BaseCrawler(CrawlerConstant.projectCode projectCode, boolean dyn) {
        this.projectCode = projectCode;
        this.dyn = dyn;
    }

    public E dataCrawler(String url) {

            url = this.newUrl(url);

        E o = this.newInstance();
        o.setProjectCode(projectCode);
        o.setUrl(url);
        o.setId(UuidUtil.getId(url));
        String html ;
        if(dyn){

            html = jsHtml(url);
        }else{
            html = staticHtml(url);
        }
        o.setContent(html);
        return o;
    }


    public void parsing(E obj){

    }

            private WebClient getWebClient(){
                WebClient webClient=new WebClient(BrowserVersion.CHROME);

                webClient.addRequestHeader("User-Agent","Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:50.0) Gecko/20100101 Firefox/50.0");
                //2.设置参数
//启动js
                webClient.getOptions().setJavaScriptEnabled(true);
//关闭css渲染
                webClient.getOptions().setCssEnabled(false);
//启动重定向
                webClient.getOptions().setRedirectEnabled(true);
//启动cookie管理
                webClient.setCookieManager(new CookieManager());
//启动ajax代理
                webClient.setAjaxController(new NicelyResynchronizingAjaxController());
//js运行时错误，是否抛出异常
                webClient.getOptions().setThrowExceptionOnScriptError(false);

                // 取消css支持
        //webClient.getOptions().setCssEnabled(false);

        return  webClient;
    }


    @SneakyThrows
    private String staticHtml(String url){
//        WebClient webClient=getWebClient();
//        //关闭js
//        webClient.getOptions().setJavaScriptEnabled(false);
//        HtmlPage page=webClient.getPage(url);
//        String html = page.asXml();
//        webClient.close();

        CloseableHttpClient httpClient=HttpClients.createDefault();
        // 创建httpClient实例
        HttpGet httpGet=new HttpGet(url);
        // 创建httpget实例
        httpGet.setHeader("User-Agent", "Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:50.0) Gecko/20100101 Firefox/50.0");
        // 设置请求头消息User-Agent
        CloseableHttpResponse response=httpClient.execute(httpGet);
        // 执行http get请求
        HttpEntity entity=response.getEntity();
        // 获取返回实体
        String data = EntityUtils.toString(entity, "utf-8");

        return data;
    }


    @SneakyThrows
    private String jsHtml(String url){
        WebClient webClient=getWebClient();

        String html=null;



            HtmlPage page=webClient.getPage(url);
           // webClient.waitForBackgroundJavaScript(2000);
Thread.sleep(5000);
            html = page.asXml();

            webClient.close();


        return html;
    }


    protected Class<E> getEntityClass()
    {
        return (Class<E>) GenericUtil.getGeneric(this.getClass(), BaseCrawler.class, 0);
    }
    /**
     * 得到泛型实例
     *
     * @return
     */
    protected E newInstance() {
        return ReflectionUtil.newInstance(getEntityClass());
    }


    protected String newUrl(String url) {
        if(!url.startsWith("http")){

            url = projectCode.getLabel()+url;
        }
        return url;
    }


    protected Document parse(String html){
        Document document = Jsoup.parse(html);
        Elements as =  document.select("a");
        for (Element a : as) {
            String url = a.attr("href");
            url = this.newUrl(url);
            a.attr("href",url);
        }
        Elements imgs =  document.select("img");
        for (Element img : imgs) {
            String url = img.attr("src");
            url = this.newUrl(url);
            img.attr("src",url);
        }
        return document;
    }

    public void crawlerPage(E o, int number, boolean next) {
        int i = 0;
        while (i++ < number) {
            String url;
            if (next) {
                url = o.getNextUrl();
            } else {
                url = o.getPreUrl();
            }
            if ("#".equals(url)) {
                continue;
            }
            o= this.dataCrawler(url);
        }
    }



    public static String getBaseUrl(String url) {
        int i = url.indexOf("?");
        String baseUrl = url.substring(0, i);
        return baseUrl;
    }


    public static String changeUrl(String url,boolean next) {

        Map<String, String> params = getUrlParams(url);

        String oldStart = params.get("start");
        String oldEnd = params.get("end");

        if(StringUtils.isBlank(oldStart)){
            oldStart = "0";
        }
        if(StringUtils.isBlank(oldEnd)){
            oldEnd = "20";
        }

        int size = Integer.parseInt(oldEnd)-Integer.parseInt(oldStart);
        int newStart;
        if(next){
            newStart = Integer.parseInt(oldEnd)+size;
        }else{
            newStart = Integer.parseInt(oldEnd)-size;
        }
        params.put("start",""+newStart);
        params.put("end",""+(newStart+size));

        return getBaseUrl(url)+"?"+toUrl(params);
    }



    public static Map<String, String> getUrlParams(String url) {
        int i = url.indexOf("?");
        if (i != -1) {
            url = url.substring(i + 1);
        }
        HashMap map = new HashMap<>();
        for (String s : url.split("&")) {
            String[] ts = s.split("=");
            if (ts.length == 2) {
                map.put(ts[0], ts[1]);
            } else {
                map.put(ts[0], "");
            }
        }
        return map;
    }

    public static String toUrl(Map<String,String> params){
        StringBuffer sb =  new StringBuffer();
        params.forEach((x,y) -> {
            sb.append(x+"="+y+"&");
        });
        return  sb.toString();
    }


    public <E> E  getValue(Map map,String... keys){

        Object val = null;
        for (String key : keys) {
            val = map.get(key);
            if(val instanceof Map){
                map = (Map)val;
            }
        }
        return (E)val;
    }


}
